package com.wzh.ojbackendjudgeservice.service.impl;

import cn.hutool.json.JSONUtil;
import com.wzh.ojCommon.common.ErrorCode;
import com.wzh.ojCommon.exception.BusinessException;
import com.wzh.ojCommon.properties.CodeSandboxProperties;
import com.wzh.ojModel.model.dto.judge.ExecuteCodeRequest;
import com.wzh.ojModel.model.dto.question.JudgeCase;
import com.wzh.ojModel.model.entity.JudgeContext;
import com.wzh.ojModel.model.entity.JudgeInfo;
import com.wzh.ojModel.model.entity.Question;
import com.wzh.ojModel.model.entity.QuestionSubmit;
import com.wzh.ojModel.model.enums.QuestionSubmitStatusEnum;
import com.wzh.ojModel.model.vo.ExecuteCodeResponse;
import com.wzh.ojbackendjudgeservice.JudgeManage;
import com.wzh.ojbackendjudgeservice.codesandbox.CodeSandbox;
import com.wzh.ojbackendjudgeservice.codesandbox.factory.CodeSandboxFactory;
import com.wzh.ojbackendjudgeservice.codesandbox.factory.CodesandboxProxy;
import com.wzh.ojbackendjudgeservice.service.JudgeService;
import com.wzh.ojbackendserviceclient.service.QuestionFeignClient;
import com.wzh.ojbackendserviceclient.service.UserFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

import static com.wzh.ojModel.model.enums.JudgeInfoMessageEnum.WAITING;
import static com.wzh.ojModel.model.enums.QuestionSubmitStatusEnum.RUNNING;


/**
 * @author wzh
 */
@Service
@Slf4j
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionFeignClient questionFeignClient;
    @Resource
    private CodeSandboxProperties codeSandboxProperties;
    @Resource
    private JudgeManage judgeManage;
    @Resource
    private UserFeignClient userFeignClient;


    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {
        QuestionSubmit submitRecord = questionFeignClient.getQuestionSubmitById(questionSubmitId);
        if (submitRecord == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");
        }
        Long questionId = submitRecord.getQuestionId();
        //获取题目信息
        Question quesInfo = questionFeignClient.getQuestionById(questionId);
        if (quesInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
        if (submitRecord.getStatus().equals(WAITING.getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目正在判题中");
        }
//         更改提交状态为判题中
        submitRecord.setStatus(RUNNING.getValue());
        questionFeignClient.updateQuestionSubmitById(submitRecord);
//         调用沙箱，获取执行结果
        CodeSandbox codeSandbox = CodeSandboxFactory.getCodeSandbox(codeSandboxProperties.getType());
        codeSandbox = new CodesandboxProxy(codeSandbox);
        String judgeCaseStr = quesInfo.getJudgeCase();
        List<JudgeCase> judgeCases = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<String> inputs = judgeCases.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(submitRecord.getCode())
                .language(submitRecord.getLanguage())
                .input(inputs).build();
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);

        List<String> outputList = executeCodeResponse.getOutputList();
        JudgeInfo judgeInfo = executeCodeResponse.getJudgeInfo();
        JudgeContext judgeContext = getJudgeContext(judgeInfo, outputList, inputs, quesInfo, judgeCases, submitRecord);

        JudgeInfo judgeInfos = null;
        try {
            judgeInfos = judgeManage.doJudge(judgeContext);
            submitRecord.setJudgeInfo(JSONUtil.toJsonStr(judgeInfos));
            submitRecord.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        } catch (Exception e) {
            log.info("判题过程中发生异常，判题失败:" + e.getMessage());
            submitRecord.setJudgeInfo(JSONUtil.toJsonStr(judgeInfos));
            submitRecord.setStatus(QuestionSubmitStatusEnum.FAILED.getValue());
        }
//        修改数据库中的判题结果
        boolean res = questionFeignClient.updateQuestionSubmitById(submitRecord);
        if (!res) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目状态更新错误");
        }
        return questionFeignClient.getQuestionSubmitById(questionSubmitId);
    }


    /**
     * 获取判题决策上下文对象
     *
     * @param judgeInfo
     * @param outputList
     * @param inputList
     * @param question
     * @param judgeCaseList
     * @return JudgeContext
     */
    public JudgeContext getJudgeContext(JudgeInfo judgeInfo, List<String> outputList, List<String> inputList, Question question, List<JudgeCase> judgeCaseList, QuestionSubmit questionSubmit) {
        return JudgeContext.builder()
                .judgeInfo(judgeInfo)
                .outputList(outputList)
                .question(question)
                .judgeCaseList(judgeCaseList).questionSubmit(questionSubmit)
                .inputList(inputList).build();
    }
}
